/* 
 *	Copyright (C) 2009-2010 miaohua
 *	http://code.google.com/p/lrcshower/
 *
 *  This Program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  This Program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

#include "stdafx.h"
#include <Streams.h>
#include <initguid.h>
//#include <comdef.h>
#include <gdiplus.h>
#include <string>
#include "AppMsgDef.h"
#include "TypeDef.h"
#include "LrcShowFilter.h"
#include "LrcShowFilterUUID.h"
#include "HelperFunctions.h"
#include "MusicBoxSetting.h"
#include "MusicBox.h"
#include "MusicBoxDlg.h"
#include "PlayListDlg.h"
#include "WinLrcShowDlg.h"
#include "DeskLrcShowDlg.h"
#include "FileDlg.h"
#include "SimpleTray.h"
#include "PlayerSettingDlg.h"
#include "MFCHelperFuncs.h"
//#include "MediaInfoDLL.h"           // Media info dll's head file
//#include "SearchEngineComHdr.h"
//#include "SimpleFileDownloader.h"
//#include "BaiduMusic.h"             // Baidu music search result parse
//#include "SogouMusic.h"             // Sogou music search result parse
//using namespace MediaInfoDLL;
using namespace std;
using namespace Gdiplus; 

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define SAFE_RELEASE(i) {if (i) i->Release(); i = NULL;}
#define JIF(x) if (FAILED(HR=(x))) \
    {_Dbg_Printf(TEXT("FAILED(0x%x) ") TEXT(#x) TEXT("\n\0"), HR); goto CLEANUP;}

MusicBoxSetting Gbl_AppProp;

// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

    // Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

    // Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{

}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()



// CMusicBoxDlg dialog

CMusicBoxDlg::CMusicBoxDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMusicBoxDlg::IDD, pParent)
    , m_PlayStatus(Player_None)
    , m_PosTimer(NULL), m_TitleTimer(NULL)
    , m_GraphBuilder(NULL), m_MediaSeek(NULL)
    , m_MediaControl(NULL), m_MediaEvent(NULL)
{
     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

     // Initialize COM
     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
     // Initialize the gdiplus system
     GdiplusStartup(&m_GdiplusToken, &m_GdiplusStartupInput, NULL);
}

CMusicBoxDlg::~CMusicBoxDlg()
{ 
     // Release COM
     CoUninitialize();
     // Shutdown gdi plus system
  	 GdiplusShutdown(m_GdiplusToken);	
}

void CMusicBoxDlg::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
     DDX_Control(pDX, IDC_PROGRESS_SLIDE, m_SeekPosBar);
     DDX_Control(pDX, IDC_VOL_CTRL, m_VolCtrl);
}

BEGIN_MESSAGE_MAP(CMusicBoxDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_WM_LBUTTONDOWN()
    ON_WM_HSCROLL()
    ON_WM_DESTROY()
    ON_WM_CONTEXTMENU()
    ON_WM_CLOSE()
	//}}AFX_MSG_MAP
    ON_BN_CLICKED(IDC_OPEN_BTN, &CMusicBoxDlg::OnBnClickedOpenBtn)
    ON_BN_CLICKED(IDC_STOP_BTN, &CMusicBoxDlg::OnBnClickedStopBtn)
    ON_BN_CLICKED(IDC_NEXT_BTN, &CMusicBoxDlg::OnBnClickedNextBtn)
    ON_BN_CLICKED(IDC_START_PAUSE_BTN, &CMusicBoxDlg::OnBnClickedStartPauseBtn)
    ON_BN_CLICKED(IDC_MUTE, &CMusicBoxDlg::OnBnClickedMute)
    ON_BN_CLICKED(IDC_LRC_SHOW, &CMusicBoxDlg::OnBnClickedLrcShow)
    ON_BN_CLICKED(IDC_PL_SHOW, &CMusicBoxDlg::OnBnClickedPlShow)
    ON_BN_CLICKED(IDC_PREV_BTN, &CMusicBoxDlg::OnBnClickedPrevBtn)
    // Right click menu message map
    ON_COMMAND(MAINMENU_PLAYER_OPTION, OnPlayerOption)
    ON_COMMAND(MAINMENU_PLAYER_MIN, OnPlayerMin)
    ON_COMMAND(MAINMENU_PLAYER_EXIT, OnPlayerExit)

    // User defined message map
    ON_MESSAGE(WM_GRAPHNOTIFY, OnGraphEvent)
    ON_MESSAGE(WM_PL_PLAYMEDIA, OnPLPlayMedia)
	ON_MESSAGE(WM_TRAYNOTIFY, OnTrayNotify)

END_MESSAGE_MAP()


// CMusicBoxDlg message handlers

BOOL CMusicBoxDlg::OnInitDialog()
{
     CDialog::OnInitDialog();

     // Add "About..." menu item to system menu.

     // IDM_ABOUTBOX must be in the system command range.
     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
     ASSERT(IDM_ABOUTBOX < 0xF000);

     CMenu* pSysMenu = GetSystemMenu(FALSE);
     if (pSysMenu != NULL)
     {
	     BOOL bNameValid;
	     CString strAboutMenu;
	     bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
	     ASSERT(bNameValid);
	     if (!strAboutMenu.IsEmpty())
	     {
		     pSysMenu->AppendMenu(MF_SEPARATOR);
		     pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
	     }
     }

     // Set the icon for this dialog.  The framework does this automatically
     // when the application's main window is not a dialog
     SetIcon(m_hIcon, TRUE);		// Set big icon
     SetIcon(m_hIcon, FALSE);		// Set small icon

     // Release any existing interfaces & initialize dshow interfaces
     // Set progress bar range
     m_SeekPosBar.SetRange(0, 1000);
     // Set volume bar range
     m_VolCtrl.SetRange(0, 200);
     int Pos = (Gbl_AppProp.GetVolume()-Gbl_AppProp.GetSilenceVol())*m_VolCtrl.GetRangeMax()/Gbl_AppProp.GetSilenceVol()*(-1);
     m_VolCtrl.SetPos(Pos);
     // Load menu
     m_RClkMenu.LoadMenu(IDR_MAIN_MENU);
     // Set system tray
	 m_SysTray.SetIcon(m_hIcon);
	 m_SysTray.SetToolTip(IDS_TRAY_TITLE);
	 m_SysTray.Show();

     // Create win lrc & desktop lrc dialog & pl dialog
     Gbl_AppProp.m_WinLrcShowDlg = std::auto_ptr<CWinLrcShowDlg>(new CWinLrcShowDlg());
     Gbl_AppProp.m_WinLrcShowDlg->Create(IDD_WINLRC_DLG, this);

     Gbl_AppProp.m_DeskLrcShowDlg = std::auto_ptr<CDeskLrcShowDlg>(new CDeskLrcShowDlg());
     Gbl_AppProp.m_DeskLrcShowDlg->Create(IDD_DESKLRC_DLG, this);

     Gbl_AppProp.m_PLDlg = std::auto_ptr<CPlayListDlg>(new CPlayListDlg());
     Gbl_AppProp.m_PLDlg->Create(IDD_PLAYLIST_DLG, this);

     return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMusicBoxDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon.  For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CMusicBoxDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMusicBoxDlg::OnQueryDragIcon()
{
     return static_cast<HCURSOR>(m_hIcon);
}


void CMusicBoxDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
     SendMessage(WM_SYSCOMMAND,0xF012,0);  
     CDialog::OnLButtonDown(nFlags, point);
}

void CMusicBoxDlg::OnBnClickedStartPauseBtn()
{
     // Check the invalidate status
     if( m_PlayStatus == Player_None || Gbl_AppProp.GetCurSongFullPath().empty() )
         return;

     // If player is running, just do pause
     if( m_PlayStatus == Player_Running ){
         if( PauseMedia() )
             ConfigPauseCtrls();
     } else {
         // The same media file, just do resume
         if( PlayMedia(Gbl_AppProp.GetCurSongFullPath().c_str()) )
         {
             /*Gbl_AppProp.StartLrcFilter();*/
             ConfigPlayCtrls();
         }
     }
}

void CMusicBoxDlg::OnBnClickedStopBtn()
{
     // Check the invalidate status
     if( m_PlayStatus == Player_None )
         return;

     if( StopMedia() )
         ConfigStopCtrls();
}

void CMusicBoxDlg::OnBnClickedPrevBtn()
{
     int SongIdx = Gbl_AppProp.GetPrevSongIdx();
     if( SongIdx != -1 )
     {
         if( PlayMedia(Gbl_AppProp.GetSongFullPath(SongIdx).c_str()) ) 
         {
             OpenNewSong(SongIdx);
             //Gbl_AppProp.NotifyPLDlg(SongIdx);
         }
     } else
         OnBnClickedStopBtn();
}

void CMusicBoxDlg::OnBnClickedNextBtn()
{
     int SongIdx = Gbl_AppProp.GetNextSongIdx();
     if( SongIdx != -1 )
     {
         if( PlayMedia(Gbl_AppProp.GetSongFullPath(SongIdx).c_str()) )
         { 
             OpenNewSong(SongIdx);
             //Gbl_AppProp.NotifyPLDlg(SongIdx);
         }
     } else
         OnBnClickedStopBtn();
}

void CMusicBoxDlg::OnBnClickedOpenBtn()
{
     // Show media file selection dialog
     CString Filters;
     Filters.LoadString(IDS_MEDIA_FILTER);
	 CFileDlg OpenFileDlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST|OFN_OVERWRITEPROMPT, Filters, this);
     // Select media file
     if( OpenFileDlg.DoModal() != IDOK ) 
         return;
     // Play media
     if( PlayMedia(OpenFileDlg.GetPathName()) )
     {
	     //unsigned int ID ;
	     //m_ThreadOnOpen = (HANDLE)_beginthreadex(NULL,0,ThreadOnOpen,this,0,&ID);
	 
         // Stop update gui(Kill any pending timer)
         StopChgTitleTimer();
         StopSeekPosTimer();
         // Add the song to current play list
         int SongIdx = Gbl_AppProp.AddOneSong((LPCTSTR)(OpenFileDlg.GetPathName()));
         // Open it
         OpenNewSong(SongIdx);
     }
}

void CMusicBoxDlg::OnBnClickedMute()
{
     if( !Gbl_AppProp.IsMute() )
         Mute();
     else
         UnMute();
}

bool RendBg(HWND RendWin)
{
     if( RendWin == NULL ) return false;
	 
     // Get memory dc
	 HDC WinDC = GetDC(RendWin);
	 HDC WinMemDC = CreateCompatibleDC(WinDC);
	     
     // Get window size
     RECT Rect;
     GetWindowRect(RendWin, &Rect);	     
     int Width = Rect.right-Rect.left;
     int Height = Rect.bottom-Rect.top;

	 // Create Dib section
	 BITMAPINFO  bmi;
	 memset(&bmi, 0, sizeof(bmi));
	 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	 bmi.bmiHeader.biWidth= Width;
	 bmi.bmiHeader.biHeight= Height;
	 bmi.bmiHeader.biPlanes=1;
	 bmi.bmiHeader.biBitCount=32;
	 bmi.bmiHeader.biCompression=BI_RGB;
		
	 BYTE * MemBits = NULL;
	 HBITMAP BitMap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&MemBits, 0, 0);
     // Select into memory dc 	
	 SelectObject(WinMemDC,BitMap);

     // Use gdi+  
     Graphics Graph(WinMemDC); 	 // Set mode
     Graph.SetSmoothingMode(SmoothingModeAntiAlias);
	 Graph.SetInterpolationMode(InterpolationModeHighQualityBicubic);

	 // Paint the background
	 SolidBrush BrushBkgnd(Gbl_AppProp.m_DeskProp.m_BgClr);
	 Graph.FillRectangle(&BrushBkgnd, 0, 0, Width, Height);

     // Set layed attribution
	 DWORD dwExStyle = GetWindowLong(RendWin, GWL_EXSTYLE);
	 if((dwExStyle&0x80000)!=0x80000)
	     SetWindowLong(RendWin, GWL_EXSTYLE, dwExStyle^0x80000);
     
     // Draw
     BLENDFUNCTION Blend = {AC_SRC_OVER,0,255,1};
     SIZE WinSize = {Width, Height};
	 POINT PtSrc = {0,0};
	 POINT PtWinPos = {Rect.left,Rect.top};
     BOOL Ret = UpdateLayeredWindow(RendWin,WinDC,&PtWinPos,
	                                &WinSize,WinMemDC,&PtSrc,0,&Blend,2);
     // Release DC
     ReleaseDC(RendWin, WinDC);
     DeleteDC(WinMemDC);
     DeleteObject(BitMap);

     return (Ret != FALSE);
}

void CMusicBoxDlg::OnBnClickedLrcShow()
{
     Gbl_AppProp.ShowLrcDlg(GetSafeHwnd());
}


void CMusicBoxDlg::OnBnClickedPlShow()
{
     Gbl_AppProp.ShowPLDlg(GetSafeHwnd());
}
    

bool CMusicBoxDlg::PlayMedia(const CString & SongPath)
{
     // Check wether it is empty     
     if( SongPath.IsEmpty() ) return false;

     // Check wether it is the same file
     if( Gbl_AppProp.GetCurSongFullPath().c_str() != SongPath )
     {
         // Stop first, if needed
         StopGraph();
         // Load the selected media file
         if( FAILED(PrepareMedia(SongPath)) )
         {
             // Error - disable play button and give feedback
             Msg_Prompt(IDS_E_PLAYFAIL, MB_OK|MB_ICONERROR|MB_APPLMODAL);
             return false;
         } 
         // Record current opened song's full path
         // Gbl_AppProp.m_SongFullPath = (const TCHAR*)SongPath;
     }

     // Set audio's volume
     SetVolume(Gbl_AppProp.GetVolume());

     // No error, just running
     if( SUCCEEDED(RunGraph()) )
         return true;
     else
         return false;
}

bool CMusicBoxDlg::PauseMedia()
{
     // Pause graph
     if( SUCCEEDED(PauseGraph()) )
         return true;
     else
         return false;  
}

bool CMusicBoxDlg::StopMedia()
{
     if( !m_MediaControl || !m_MediaSeek )
         return true;

     // Stop playback immediately with IMediaControl::Stop().
     HRESULT HR = StopGraph();
     if( FAILED(HR) )
     {
         MsgOutput(TEXT("Failed to stop graph !  hr=0x%x\r\n"), HR);
         return false;
     }

     // Wait for the stop to propagate to all filters
     OAFilterState Fs;
     HR = m_MediaControl->GetState(500, &Fs);
     if( FAILED(HR) )
     {
         MsgOutput(TEXT("Failed to read graph state!  hr=0x%x\r\n"), HR);
         return false;
     }

     // Reset to beginning of media clip
     LONGLONG Pos=0;
     HR = m_MediaSeek->SetPositions(&Pos, AM_SEEKING_AbsolutePositioning,
                                    NULL, AM_SEEKING_NoPositioning);
     if( FAILED(HR) )
     {
         MsgOutput(TEXT("Failed to seek to beginning of media!  hr=0x%x\r\n"), HR);
         return false;
     }
     // Display the first frame of the media clip, if it contains video.
     // StopWhenReady() pauses all filters internally (which allows the video
     // renderer to queue and display the first video frame), after which
     // it sets the filters to the stopped state.  This enables easy preview
     // of the video's poster frame.
     HR = m_MediaControl->StopWhenReady();
     if( FAILED(HR) )
     {
         MsgOutput(TEXT("Failed in StopWhenReady!  hr=0x%x\r\n"), HR);
         return false;
     }
     
     return true;
}

void CMusicBoxDlg::ConfigPlayCtrls()
{
     // Set the button title of play to pause
     CString Title;
     Title.LoadString(IDS_PAUSEBTN_TITLE);
     SetDlgItemText(IDC_START_PAUSE_BTN, Title);
     // Kill any pending timer event
     StopChgTitleTimer();
     StopSeekPosTimer();
     // Change title
     ChgTitle();
     // Show current position
     ShowCurPos();
     // Configure controls in run mode
     StartChgTitleTimer();
     StartSeekPosTimer();
}

void CMusicBoxDlg::ConfigPauseCtrls()
{
     // Set the button title of pause to play
     CString Title;
     Title.LoadString(IDS_PLAYBTN_TITLE);
     SetDlgItemText(IDC_START_PAUSE_BTN, Title);
}

void CMusicBoxDlg::ConfigStopCtrls()
{
     // Set the button title of pause to play
     CString Title;
     Title.LoadString(IDS_PLAYBTN_TITLE);
     SetDlgItemText(IDC_START_PAUSE_BTN, Title);
     // Set progress bar to start point
     m_SeekPosBar.SetPos(0);
}

void CMusicBoxDlg::StartChgTitleTimer()
{
     // Kill any pending timer event
     StopChgTitleTimer();

     // Create a new timer(duration is five second)
     const int Delay = 5000; 
     m_TitleTimer = timeSetEvent(Delay, 0, (LPTIMECALLBACK)ChgTitleTimeOut, (DWORD)this, TIME_PERIODIC);
}

void CMusicBoxDlg::StopChgTitleTimer()
{
     if( m_TitleTimer )
     {
         timeKillEvent(m_TitleTimer);
         m_TitleTimer = NULL;   
     }
}

void CMusicBoxDlg::StartSeekPosTimer()
{
     // Kill any pending timer event
     StopSeekPosTimer();

     // Create a new timer(duration is one second)
     const int Delay = 1000; 
     m_PosTimer = timeSetEvent(Delay, 0, (LPTIMECALLBACK)SeekPosTimeOut, (DWORD)this, TIME_PERIODIC);
}

void CMusicBoxDlg::StopSeekPosTimer()
{
     if( m_PosTimer )
     {
         timeKillEvent(m_PosTimer);
         m_PosTimer = NULL;   
     }
}

void CMusicBoxDlg::SeekPosTimeOut(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
     UNREFERENCED_PARAMETER(dw2);
     UNREFERENCED_PARAMETER(dw1);
     UNREFERENCED_PARAMETER(msg);
     UNREFERENCED_PARAMETER(wTimerID);
     CMusicBoxDlg * Self = (CMusicBoxDlg*)dwUser;
     Self->ShowCurPos();
}

void CMusicBoxDlg::ChgTitleTimeOut(UINT wTimerID, UINT msg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
     UNREFERENCED_PARAMETER(dw2);
     UNREFERENCED_PARAMETER(dw1);
     UNREFERENCED_PARAMETER(msg);
     UNREFERENCED_PARAMETER(wTimerID);
     CMusicBoxDlg * Self = (CMusicBoxDlg*)dwUser;
     Self->ChgTitle();
}

void CMusicBoxDlg::ShowCurPos()
{
     // Read the current stream position
     REFERENCE_TIME Now = 0;
     if( m_MediaSeek )
         m_MediaSeek->GetCurrentPosition(&Now);

     // Convert position into a percentage value and update slider position
     REFERENCE_TIME Dura = Gbl_AppProp.GetSongDura();
     if( Dura != 0 )
         m_SeekPosBar.SetPos((int)(Now*1.0/10/Dura));
     else
         m_SeekPosBar.SetPos(0);

     // Convert the LONGLONG duration into human-readable format
     CString Time = FormatTime(Now/10000).c_str();

     // Update the time display
     SetDlgItemText(IDC_TIME_TIP, Time);
}

void CMusicBoxDlg::ChgTitle()
{
     tstring Title = Gbl_AppProp.GetSongNextProp();
     SetDlgItemText(IDC_SONG_TITLE, Title.c_str());
}

HRESULT CMusicBoxDlg::InitDirectShow()
{
     m_GraphBuilder = NULL;
     m_MediaSeek = NULL;
     m_MediaControl = NULL;
     m_MediaEvent = NULL;

     HRESULT HR = S_OK;
     JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_GraphBuilder));
     JIF(m_GraphBuilder->QueryInterface(IID_IMediaControl, (void **)&m_MediaControl));
     JIF(m_GraphBuilder->QueryInterface(IID_IMediaSeeking, (void **)&m_MediaSeek));
     JIF(m_GraphBuilder->QueryInterface(IID_IMediaEventEx, (void **)&m_MediaEvent));

     return S_OK;

CLEANUP:
     FreeDirectShow();
     return HR;
}


HRESULT CMusicBoxDlg::FreeDirectShow()
{
     HRESULT HR = S_OK;

     // Disable event callbacks
     if( m_MediaEvent )
         HR = m_MediaEvent->SetNotifyWindow((OAHWND)NULL, 0, 0);

     // Safely release the com handlers
     SAFE_RELEASE(m_MediaControl);
     SAFE_RELEASE(m_MediaSeek);
     SAFE_RELEASE(m_MediaEvent);
     SAFE_RELEASE(m_GraphBuilder);

     return HR;
}


void CMusicBoxDlg::ResetDirectShow()
{
     // Destroy the current filter graph its filters.
     FreeDirectShow();
     // Reinitialize graph builder and query for interfaces
     InitDirectShow();
}

HRESULT CMusicBoxDlg::PrepareMedia(const CString & MediaFile)
{
     ResetDirectShow();
     // Allow DirectShow to create the FilterGraph for this media file
     HRESULT HR = m_GraphBuilder->RenderFile(MediaFile, NULL);
     if( FAILED(HR) ) 
     {
         MsgOutput(TEXT("*** Failed(%08lx) in RenderFile(%s)!\r\n"), HR, (LPCTSTR)MediaFile);
         return HR;
     }

     // Try to add the lrc show filter
     HR = Gbl_AppProp.m_LrcShowFilter.AddLrcShowFilter(m_GraphBuilder);
     if( FAILED(HR) ) 
         MsgOutput(TEXT("*** Failed(%08lx) in add lrc show filter!\r\n"), HR);

     // Have the graph signal event via window callbacks
     HR = m_MediaEvent->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);

     // Reset to first frame of movie( go to starting point of media )
     LONGLONG Pos = 0;
     HR = m_MediaSeek->SetPositions(&Pos, 
                            AM_SEEKING_AbsolutePositioning ,
                            NULL, 
                            AM_SEEKING_NoPositioning);

     return HR;
}


LRESULT CMusicBoxDlg::OnGraphEvent(WPARAM wParam, LPARAM lParam)
{
     // Since we may have a scenario where we're shutting down the application,
     // but events are still being generated, make sure that the event
     // interface is still valid before using it.  It's possible that
     // the interface could be freed during shutdown but later referenced in
     // this callback before the app completely exits.
     if( !m_MediaSeek )
         return S_OK;

     LONG evCode;
     LONG_PTR evParam1, evParam2;
     HRESULT HR = S_OK;
     while(SUCCEEDED(m_MediaEvent->GetEvent(&evCode, &evParam1, &evParam2, 0)))
     {
        // Spin through the events
        // If it is the end of current media
        if( EC_COMPLETE == evCode )
        {
            LONGLONG Pos = 0;

            // Reset to first frame of movie( go to starting point of media )
            HR = m_MediaSeek->SetPositions(&Pos, 
                                           AM_SEEKING_AbsolutePositioning ,
                                           NULL, 
                                           AM_SEEKING_NoPositioning);
            // If just looping, reset to beginning point of current media and continue playing
            if( Gbl_AppProp.GetPlayMode() == LOOP )
            {

                if( FAILED(HR) )
                {
                    // Some custom filters (like the Windows CE MIDI filter)
                    // may not implement seeking interfaces (IMediaSeeking)
                    // to allow seeking to the start.  In that case, just stop
                    // and restart for the same effect.  This should not be
                    // necessary in most cases.
                    StopGraph();
                    RunGraph();
                }
            } else if( Gbl_AppProp.GetPlayMode()&LIST ) {
                // If we are playing a list, tell the app to select the next file in the list
                OnBnClickedNextBtn();
            } else {
                // Stop playing and reset configuration
                OnBnClickedStopBtn();
            }
        }

        // Free memory associated with this event
        HR = m_MediaEvent->FreeEventParams(evCode, evParam1, evParam2);

     }
     return HR;
}

HRESULT CMusicBoxDlg::RunGraph()
{
     if( !m_MediaControl )
         return S_FALSE;
    
     if( m_PlayStatus == Player_Running )
         return S_OK;

     //Start playback
     HRESULT HR = m_MediaControl->Run();
     if( FAILED(HR) )
     {
         MsgOutput(L"\r\n*** Failed(%08lx) in Run()!\r\n", HR);
         return HR;
      }

      // Set play state
      m_PlayStatus = Player_Running;

     return HR;
}

HRESULT CMusicBoxDlg::StopGraph()
{
     if( !m_MediaControl )
         return S_FALSE;

     if( m_PlayStatus == Player_Stopped )
         return S_OK;

     // Stop playback
     HRESULT HR = m_MediaControl->Stop();
     if( FAILED(HR) )
     {
         MsgOutput(TEXT("\r\n*** Failed(%08lx) in Stop()!\r\n"), HR);
         return HR;
     }

     // Set play state
     m_PlayStatus = Player_Stopped;

     return HR;
}

HRESULT CMusicBoxDlg::PauseGraph()
{
     if( !m_MediaControl || m_PlayStatus != Player_Running )
         return S_FALSE;

     HRESULT HR = m_MediaControl->Pause();
     if( FAILED(HR) )
     {
         MsgOutput(TEXT("\r\n*** Failed(%08lx) in Pause()!\r\n"), HR);
         return HR;
     }

     // Set play state
     m_PlayStatus = Player_Paused;

     return HR;
}

HRESULT CMusicBoxDlg::Mute()
{
     Gbl_AppProp.SetMute(true);
     return SetVolume(MusicBoxSetting::GetSilenceVol());
}

HRESULT CMusicBoxDlg::UnMute()
{
     Gbl_AppProp.SetMute(false);
     return SetVolume(Gbl_AppProp.GetVolume());
}

HRESULT CMusicBoxDlg::SetVolume(long Volume)
{
     // If no graph, just return quietly
     if( !m_GraphBuilder )
         return S_OK;
     
     // Get audio interface
     IBasicAudio * BA = NULL;
     HRESULT HR = m_GraphBuilder->QueryInterface(IID_IBasicAudio, (void **)&BA);
     if( FAILED(HR) )
         return HR;

     // Read current volume
     long Vol;
     HR = BA->get_Volume(&Vol);
     if( HR == E_NOTIMPL )
     {
         // Fail quietly if this is a video-only media file
         BA->Release();
         return HR;
     } else if( FAILED(HR) ) {
         MsgOutput(TEXT("Failed in pBA->get_Volume!  hr=0x%x\r\n"), HR);
         BA->Release();
         return HR;
     }

     // Set new volume
     HR = BA->put_Volume(Volume);
     if( FAILED(HR) )
         MsgOutput(TEXT("Failed in BA->put_Volume!  hr=0x%x\r\n"), HR);
     BA->Release();
    
     return HR;
}

   
unsigned int CMusicBoxDlg::ThreadOnOpen(void* Param)
{
     //CMusicBoxDlg * Self = (CMusicBoxDlg*)Param;
     //Self->OnOpen();
     return 0;
}

void CMusicBoxDlg::OpenNewSong(int SongIdx, int PLIdx)            
{
     // Open the song(set current play list index,song index, stop lrc filter)
     Gbl_AppProp.OpenOneSong(SongIdx,PLIdx);
     // Send Message to Play list dialog what we are playing now
     Gbl_AppProp.NotifyPLDlg(SongIdx);
     // Configure controls for play state
     ConfigPlayCtrls();
     // Do lrc search(local or online, and automaticly start lrc show filter)
     Gbl_AppProp.DoLrcSearch(SongIdx,PLIdx);
     // Start lrc show
     Gbl_AppProp.StartLrcShow();
}      

void CMusicBoxDlg::OnDestroy()
{
     // Stop timers
     StopChgTitleTimer();
     StopSeekPosTimer();
     // Stop Graph;
     StopGraph();
     // Remove lrc show filter
     Gbl_AppProp.m_LrcShowFilter.RemoveLrcShowFilter(m_GraphBuilder);
     // m_GraphBuilder->RemoveFilter(Gbl_AppProp.m_LrcShowFilter);
     //if( Gbl_AppProp.m_LrcShowFilter )
     Gbl_AppProp.m_LrcShowFilter.Release();
     // Free dshow interfaces
     FreeDirectShow();

     CDialog::OnDestroy();
}

void CMusicBoxDlg::OnContextMenu(CWnd* /*pWnd*/, CPoint Point)
{
     CMenu* Popup = m_RClkMenu.GetSubMenu(0);
     ASSERT( Popup != NULL );
     Popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, Point.x, Point.y, this );
}

BOOL CMusicBoxDlg::PreTranslateMessage(MSG* pMsg)   
{  
     if(pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_RETURN)     
        return TRUE;  
     if(pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_ESCAPE)     
        return TRUE;  
     return CDialog::PreTranslateMessage(pMsg);  
}  

LRESULT CMusicBoxDlg::OnTrayNotify(WPARAM wParam, LPARAM lParam)
{	// Switch lParam, which contains the event that occured
	// wParam would hold the icon's ID, but since we have
	// only one icon, we don't need to check that
    if( wParam != IDR_MAINFRAME )  
        return 1;  	
    switch ( lParam )
	{
	    case WM_LBUTTONDBLCLK:
		{	// double click, activate window
			// we would do here the same thing as if
			// the user clicked the "show dialog" menu
			// so don't duplicate the code
	        OnShowMainWin();
		}
		break;
	    case WM_RBUTTONUP:
		{	
            // Right click, show popup menu
            CMenu* Popup = m_RClkMenu.GetSubMenu(0);
            ASSERT( Popup != NULL );
			CPoint Loc;
			GetCursorPos(&Loc);
            Popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, Loc.x, Loc.y, this );
		}
		break;	
	default:
		// Do nothing
		break;
	}
    return 0;
}

void CMusicBoxDlg::OnShowMainWin()
{
	 SetForegroundWindow();
	 ShowWindow(SW_SHOW);
	
	 // if it is minimized restore it
	 if( IsIconic() )
		 ShowWindow(SW_RESTORE);
}

void CMusicBoxDlg::OnPlayerOption()
{
     CPlayerSettingDlg PropSheet;
	 PropSheet.DoModal();
}

void CMusicBoxDlg::OnPlayerMin()
{
     OnClose();
}

void CMusicBoxDlg::OnPlayerExit()
{
     EndDialog(IDOK);
}

void CMusicBoxDlg::OnClose()
{
	 m_SysTray.ShowBalloonTip(IDS_TRAY_TITLE, _T("MusicBox"), 5000);
     ShowWindow(SW_HIDE);	
}

LRESULT CMusicBoxDlg::OnPLPlayMedia(WPARAM wParam, LPARAM lParam)
{
     tstring FullPath = Gbl_AppProp.GetSongFullPath(wParam, lParam);
     // Play media
     if( PlayMedia(FullPath.c_str()) )
         OpenNewSong(wParam, lParam);

     return 0;
}


void CMusicBoxDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
     if( pScrollBar->GetDlgCtrlID() == IDC_PROGRESS_SLIDE )
         HandleSeekPosBar(nSBCode);
     else if( pScrollBar->GetDlgCtrlID() == IDC_VOL_CTRL )
         HandleVolumeSlider(nSBCode);
     CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CMusicBoxDlg::HandleSeekPosBar(UINT SBCode)
{
     static bool StartOfScroll = true;
     if( (!m_MediaControl) || (!m_MediaSeek) )
         return;

     // If the file is not seekable, the trackbar is disabled. 
     DWORD Position = m_SeekPosBar.GetPos();

     // Pause when the scroll action begins.
     if( StartOfScroll ) 
     {       
         StartOfScroll = false;
         m_MediaControl->Pause();
     }

     // Update the position continuously.
     REFERENCE_TIME rtNew = Gbl_AppProp.GetSongDura() * Position * 10; // (m_DurationTime * dwPosition) / 1000*10000 ---> convert ns to ms

     m_MediaSeek->SetPositions(&rtNew, AM_SEEKING_AbsolutePositioning,
                                   NULL, AM_SEEKING_NoPositioning);

     // Restore the state at the end.
     if( SBCode == SB_THUMBTRACK )
     {
        if( m_PlayStatus == Player_Stopped )
            m_MediaControl->Stop();
        else if( m_PlayStatus == Player_Running ) 
            m_MediaControl->Run();

        StartOfScroll = true;
     }

     // Update the 'current position' string on the main dialog.
     ShowCurPos();
}

void CMusicBoxDlg::HandleVolumeSlider(UINT SBCode)
{
     // Disregard ENDSCROLL messages, which are redundant
     if( SBCode == SB_ENDSCROLL )
         return;

     //get current volume from the volume control
     int Position = m_VolCtrl.GetPos();
     Gbl_AppProp.SetVolume(MusicBoxSetting::GetSilenceVol()+Position*MusicBoxSetting::GetSilenceVol()*(-1)/m_VolCtrl.GetRangeMax());

     // Set new volume
     SetVolume(Gbl_AppProp.GetVolume());
}